package com.rock.app.base;

import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.alibaba.fastjson.JSON;
import com.eova.aop.eova.EovaContext;
import com.eova.common.base.BaseCache;
import com.eova.common.utils.xx;
import com.eova.common.utils.db.SqlUtil;
import com.eova.common.utils.time.DateUtil;
import com.eova.config.EovaConfig;
import com.eova.config.EovaConst;
import com.eova.core.meta.MetaDataType;
import com.eova.engine.DynamicParse;
import com.eova.engine.EovaExp;
import com.eova.i18n.I18NBuilder;
import com.eova.model.MetaField;
import com.eova.model.MetaObject;
import com.eova.model.RoleObjField;
import com.eova.model.User;
import com.eova.template.common.util.TemplateUtil;
import com.jfinal.core.Controller;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

import cn.hutool.core.util.StrUtil;

public class MetaApiUtil {

	/**
	 * 通过Form构建数据
	 *
	 * @param c 控制器
	 * @param eis 对象属性
	 * @param record 当前操作对象数据集
	 * @param pkName 主键字段名
	 * @param postMap 
	 * @return 视图表数据分组
	 */
	public static Map<String, Record> buildData(Controller c, MetaObject object, Record record, String pkName, boolean isInsert) {
		Map<String, Record> datas = new HashMap<String, Record>();

		//安全模式（默认是安全模式），主要是在更新模式下：安全模式只提取可更新的字段，设置成非安全模式主要原因是更新可能由多种更新（标准更新：a,b,c,d字段），但是其他业务场景比如审核 则需要其他的字段：e，f
		//所以安全模式只更新abcd字段，非安全模式则由提交参数者确定~~
		Integer safeMode = object.getInt("safe_mode");
		if(safeMode == null)
			safeMode = 1;
		
		String ds = object.getDs();
//		 String dsType =  EovaConfig.MAIN_DBTYPE;
//		 if(object.getDs().equals("eova") || StringUtils.isEmpty(object.getDs()))
//			 dsType =  EovaConfig.EOVA_DBTYPE;

        //数据记录map
        String postData = c.getRawData();
        Map postMap = JSON.parseObject(postData);
		  
		// 获取字段当前的值
		for (MetaField item : object.getFields()) {
			// System.out.println(item.getEn() +'='+ c.getPara(item.getEn()));
			String type = item.getStr("type");// 控件类型
			String key = item.getEn();// 字段名
			String data_type_name =(String) item.get("data_type_name");
			String pk = object.getPk();// 控件类型
			
			int dataSize = item.getDataSize();
			
			// 获当前字段 Requset Parameter Value，禁用=null,不填="" ,存在数组的参数组织成1，2
			//Object value = c.getPara(key);
			Object value = postMap.get(key);
			
//			String[] values = c.getParaValues(key);
//			if(values == null)
//				value = null;
//			else {
//				value = xx.join(values, ',');
//			}
				
			if(isInsert){//新增
				if(xx.isMssql(ds)){
					if(key.equalsIgnoreCase(pk) && xx.isEmpty(value)){
							if("uniqueidentifier".equalsIgnoreCase(data_type_name)){
								value = UUID.randomUUID().toString();
							}else if(("varchar".equalsIgnoreCase(data_type_name) || "nvarchar".equalsIgnoreCase(data_type_name)) && dataSize == 36){
								value = UUID.randomUUID().toString();
							}
					}else if("DATETIME".equalsIgnoreCase(data_type_name) && key.toLowerCase().indexOf("create")!=-1){
						value = DateUtil.format(new Date(), DateUtil.YYYY_MM_DD_HH_MM_SS);
					}else if("DATETIME".equalsIgnoreCase(data_type_name) && key.toLowerCase().indexOf("modify")!=-1){
						value = null;
					}
				
				}
			}else{//更新
				if(xx.isMssql(ds)){
//					 if("DATETIME".equalsIgnoreCase(data_type_name) && key.toLowerCase().indexOf("modify")!=-1){
//						value = DateUtil.format(new Date(), DateUtil.YYYY_MM_DD_HH_MM_SS);
//					 }else if("DATETIME".equalsIgnoreCase(data_type_name) && key.toLowerCase().indexOf("create")!=-1){
//						value = null;
//					 }
				}
			}
			

			
			
			// 值的预处理
			value = TemplateUtil.convertValue(item, value,safeMode);
			
			// 自动类型转换
			value = MetaDataType.convert(item, value,ds);
			// System.out.println(String.format("FormData：%s=%s", key, value));
			// 新增跳过自增长字段(新增时隐藏)
			if (value == null && type.equals(MetaField.TYPE_AUTO)) {
				continue;
			}
			
			//0-正常，10-只读，20-隐藏，50-禁用 ，禁用的情况下值无效（非安全模式也提取）
			if(isInsert){
				int addStatus = item.getInt("add_status");
				if(addStatus == 50 && safeMode == 1){
					continue;
				}
			}else{
				int updateStatus = item.getInt("update_status");
				if(updateStatus == 50 && safeMode == 1){
					continue;
				}
			}
			
			
			
			
			
			
			
			
			// 新增时，移除禁止新增的字段
//			 boolean isAdd = item.getBoolean("is_add");
//			 if (isInsert || isAdd) {
//				 //record.remove(key);
//			     //continue;
//				 
//				 if( "uniqueidentifier".equals(data_type_name) 
//							&& StringUtils.isEmpty((String)value) 
//							&& key.equalsIgnoreCase(pk) ){
//						value = UUID.randomUUID().toString();
//					}
//			 }
			 
			 
			// 当前字段为空(禁用/隐藏/非字符并未填写 且没有默认值),说明不需要持久化，直接跳过
				if (value == null) {
					continue;
				}
			 
			// 更新时，移除禁止更新的字段
			// boolean isUpdate = item.getBoolean("is_update");
			// if (!isInsert && !isUpdate) {
			// record.remove(key);
			// continue;
			// }

			// 全量的数据,mssql字段全部添加"[]",主键不修改，jfinal后面会校验
//			if(!object.getDs().equals("eova") && !object.getPk().equals(key))
//				record.set("["+key+"]", value);
//			else
				record.set(key, value);
		}
		return datas;
	}
	
	/**
	 * 获取添加页面的元字段集(rock改造版本，将表达式json一并返回)
	 * 
	 * @param objectCode
	 * @param c
	 * @return
	 */
	public static List<MetaField> getFieldAddList(String objectCode, Controller c) {
		MetaObject object = MetaObject.dao.getByCode(objectCode);
		User user = (User) c.getSession().getAttribute(EovaConst.USER);
		List<MetaField> fields = MetaField.dao.queryFields(objectCode);

		List<Integer> roleFields = null;
		if (user != null) {
//			roleFields = RoleObjField.dao.queryIdByRids(user.getRids(), objectCode);
		}

		// 安全保护，去掉界面不需要的字段

		Iterator<MetaField> it = fields.iterator();
		while (it.hasNext()) {
			MetaField f = it.next();
//			f.remove("exp"); //暂时保留
			f.remove("table_name");
			f.remove("data_type");
			f.remove("data_type_name");
			f.remove("data_size");
			f.remove("date_decimal");

			// added by jializheng 只保留新增状态为正常的字段
			// eova_fields表中字段新增状态add_status，0代表正常
			if (f.getInt("add_status") != 0) {
				it.remove();
				continue;
			}

			// added by jializheng 将表达式json一并返回
			if (!xx.isEmpty(f.get("exp"))) {
				List<Record> expValueList = MetaApiUtil.comboJson(f,c);
				Map<String, Object> expValueMap = new HashMap<String, Object>();
				expValueMap.put("exp_value", expValueList);
				f.put(expValueMap);

				//bind_index是前端点选的索引
				for (int i = 0; i < expValueList.size(); i++) {
					Record rc = expValueList.get(i);
					if (rc.getStr("id").equals(f.get("defaulter"))) {
						f.put("bind_index", i);
					}
				}
			}
			
			// 为了适应前端动态进行多个下拉框、图片等数据绑定，额外增加字段bind_data bind_index
			//bind_data是实际绑定的值，对应数据字典的值
			f.put("bind_data", f.get("defaulter"));

			// 对于日期框，默认置当天
			if (f.getType().equals("日期框")) {
				f.put("bind_data", DateUtil.format(new Date(), "yyyy-MM-dd"));
			}
			
			//角色字段权限控制
			if (roleFields != null && roleFields.size() != 0) {
				if (!roleFields.contains(f.get("id"))) {
					f.put("is_show", false);
				}
			}
		}
		return fields;
	}

	/**
	 * 获取更新页面的元字段集(rock改造版本，将表达式json一并返回)
	 * 
	 * @param objectCode
	 * @param c
	 * @return
	 */
	public static Map<String, List<MetaField>> getFieldUpdateList(String objectCode, Record record, Controller c) {
		MetaObject object = MetaObject.dao.getByCode(objectCode);
		List<MetaField> updateFields = MetaField.dao.queryFields(objectCode);
		List<MetaField> updateHiddenFields = new ArrayList<MetaField>();

		// 安全保护，去掉界面不需要的字段
		Iterator<MetaField> it = updateFields.iterator();
		while (it.hasNext()) {
			MetaField f = it.next();
//					f.remove("exp"); //暂时保留
			f.remove("table_name");
			f.remove("data_type");
			f.remove("data_type_name");
			f.remove("data_size");
			f.remove("date_decimal");

			// added by jadison 只保留更新状态为正常的字段
			// eova_fields表中字段更新状态add_status，0代表正常
			if (f.getInt("update_status") != 0) {
				it.remove();
				
				//加入到隐藏字段集
				// 将此字段值放入fields，前端编辑界面直接使用（但不显示）
				f.put("crdata", record.getStr(f.getEn()));
				updateHiddenFields.add(f);
				
				continue;
			}

			// added by jializheng 将表达式json一并返回
			if (!xx.isEmpty(f.get("exp"))) {
				List<Record> expValueList = comboJson(f, c);
				Map<String, Object> expValueMap = new HashMap<String, Object>();
				expValueMap.put("exp_value", expValueList);
				f.put(expValueMap);

				// bind_index是前端点选的索引
				f.put("bind_index", null);
				for (int i = 0; i < expValueList.size(); i++) {
					Record rc = expValueList.get(i);
					if (rc.getStr("id").equals(record.getStr(f.getEn()))) {
						f.put("bind_index", i);
					}
				}
			}

			// 为了适应前端动态进行多个下拉框、图片等数据绑定，额外增加字段bind_data bind_index
			// bind_data是实际绑定的值，对应数据字典的值
			// bind_index是前端点选的索引
			String currentData = record.getStr(f.getEn()) == null ? "" : record.getStr(f.getEn());
			f.put("bind_data", currentData);

			// 将此字段值放入fields，前端编辑界面直接使用
			f.put("crdata", currentData);
			
			//added by jadison 20201119
			//查询返回时，统一转换日期框格式
			if(MetaField.TYPE_DATE.equals(f.getStr("type"))) {//日期框
				f.put("crdata", DateUtil.format(record.getDate(f.getEn()), DateUtil.YYYY_MM_DD));
			}
			//查询返回时，统一转换时间框格式
			if(MetaField.TYPE_TIME.equals(f.getStr("type"))) {//日期框
				f.put("crdata", DateUtil.format(record.getDate(f.getEn()), DateUtil.YYYY_MM_DD_HH_MM_SS));
			}

		}
		
		Map<String,List<MetaField>> um = new HashMap<String,List<MetaField>>();
		um.put("updateFields", updateFields);
		um.put("updateHiddenFields", updateHiddenFields);

		return um;
	}
	

	/**
	 * 新增或更新时判断是否满足必填要求
	 * 
	 * @param objectCode 元数据编码
	 * @param record     数据记录
	 * @return
	 */
	public static Map<String, Object> checkFieldRequiredAdd(String objectCode, Record record) {
		MetaObject object = MetaObject.dao.getByCode(objectCode);
		List<MetaField> fields = MetaField.dao.queryFields(objectCode);

		Map<String, Object> res = new HashMap<String, Object>();
		res.put("isPass", true);

		// 安全保护，去掉界面不需要的字段
		Iterator<MetaField> it = fields.iterator();
		while (it.hasNext()) {
			MetaField f = it.next();
			// id不进行判断，只判断新增状态是正常的
			if (f.getBoolean("is_required") && !f.getEn().equals("id")) {
				
				if (StrUtil.isBlankIfStr(record.get(f.getEn()))) {
					//如果是空，并且有默认值，置成默认值
					if(StrUtil.isNotBlank(f.get("defaulter"))) {
						record.set(f.getEn(), f.get("defaulter"));
						continue;
					}
					//只判断新增状态是正常的
					if(f.getInt("add_status") != 0) {
						continue;
					}
					res.put("isPass", false);
					res.put("reqEn", f.getEn());
					res.put("reqCn", f.getCn());
					return res;
				}
			}
		}
		return res;
	}
	

	/**
	 * 更新时判断是否满足必填要求
	 * 
	 * @param objectCode 元数据编码
	 * @param record     数据记录
	 * @return
	 */
	public static Map<String, Object> checkFieldRequiredUpdate(String objectCode, Record record) {
		MetaObject object = MetaObject.dao.getByCode(objectCode);
		List<MetaField> fields = MetaField.dao.queryFields(objectCode);

		Map<String, Object> res = new HashMap<String, Object>();
		res.put("isPass", true);

		// 安全保护，去掉界面不需要的字段
		Iterator<MetaField> it = fields.iterator();
		while (it.hasNext()) {
			MetaField f = it.next();
			// id不进行判断，隐藏或禁用字段不进行判断
			if (f.getBoolean("is_required") && !f.getEn().equals("id") && f.getInt("update_status")==0) {
				if (StrUtil.isBlankIfStr(record.get(f.getEn()))) {
					//如果是空，并且有默认值，置成默认值
					if(StrUtil.isNotBlank(f.get("defaulter"))) {
						record.set(f.getEn(), f.get("defaulter"));
						continue;
					}
					res.put("isPass", false);
					res.put("reqEn", f.getEn());
					res.put("reqCn", f.getCn());
					return res;
				}
			}
		}
		return res;
	}

	/**
	 * Combo Load Data Get JSON
	 */
	public static List<Record> comboJson(MetaField ei, Controller c) {
		String objectCode = c.getPara(0);
		String en = ei.getEn();
		String exp = c.getPara("exp");

		try {
			List<Object> paras = new ArrayList<Object>();
			// 构建表达式
			exp = buildExp(paras, exp, objectCode, en);
			// 动态解析变量和逻辑运算
			exp = buildExp(c, exp);

			// 解析表达式
			EovaExp se = new EovaExp(exp, true);

			String sql = se.sql;

			// 全局数据拦截条件
			if (EovaConfig.getEovaIntercept() != null) {
				EovaContext ec = new EovaContext(c);
				ec.exp = se;
				List<String> conList = EovaConfig.getEovaIntercept().filterExp(ec);
				for(String con : conList) {
					sql = SqlUtil.addCondition(sql, con);
				}
			}
			// 缓存配置
			String cache = se.getPara("cache");
			List<Record> list = null;
			if (xx.isEmpty(cache)) {
				list = Db.use(se.ds).find(sql, xx.toArray(paras));
			} else {
				list = Db.use(se.ds).findByCache(cache, sql, sql, xx.toArray(paras));
			}

			I18NBuilder.records(list, "cn");

			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取表达式
	 * 
	 * @param parmList   SQL动态参数
	 * @param exp        自定义表达式
	 * @param objectCode 元对象编码
	 * @param field      元字段名
	 * @return
	 */
	private static String buildExp(List<Object> parmList, String exp, String objectCode, String field) {
		if (xx.isEmpty(exp)) {
			// 根据表达式获取exp
			MetaField ei = MetaField.dao.getByObjectCodeAndEn(objectCode, field);
			exp = ei.getStr("exp");
		} else {
			exp = exp.trim();
			// 预处理表达式
			try {
				String[] strs = exp.split(",");
				if (strs.length > 0) {
					exp = EovaConfig.getExps().get(strs[0]);
					if (xx.isEmpty(exp)) {
						System.err.println(String.format("无法获取到表达式,请检查表达式配置,表达式Key=%s,添加新的表达式后重启服务才能生效!", strs[0]));
						throw new RuntimeException();
					}
					for (int i = 1; i < strs.length; i++) {
						parmList.add(getSqlParam(strs[i]));
					}
				}
			} catch (Exception e) {
				throw new RuntimeException("预处理自定义查找框表达式异常，Exp=" + exp);
			}
		}
		return exp;
	}

	private static String buildExp(Controller c, String exp) {
		return DynamicParse.buildSql(exp, (User) c.getSessionAttr(EovaConst.USER));
	}

	/**
	 * 获取SQL参数，优先Integer，不能转就当String
	 *
	 * @param str
	 * @return
	 */
	private static Object getSqlParam(String str) {
		try {
			return Integer.parseInt(str);
		} catch (Exception e) {
			return str;
		}
	}

	/**
	 * 根据表达式构建下拉框所需JSON数据
	 *
	 * @param exp        表达式
	 * @param parmList   sql参数
	 * @param isMultiple 是否多选
	 * @param c          支持从参数中增加条件
	 * @return 下拉JSON
	 */
	public static List<Record> buildComboData(String exp, List<Object> parmList, boolean isMultiple, Controller c) {
		exp = exp.trim();

		// 动态解析变量和逻辑运算
		exp = DynamicParse.buildSql(exp, (Object) c.getSessionAttr(EovaConst.USER));

		// 解析表达式
		EovaExp se = new EovaExp(exp);
//			String sql = se.sql;

		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append(se.select);
		sqlBuilder.append(se.from);
		if (xx.isEmpty(se.where))
			sqlBuilder.append(" where 1=1 ");
		else
			sqlBuilder.append(se.where);

		// 暂时不全字段匹配了，只检测是否 EovaExp.third (即为父节点)
		Enumeration<String> ps = c.getParaNames();
		while (ps.hasMoreElements()) {
			String paramName = ps.nextElement();
			if (paramName.startsWith("query_") && paramName.endsWith(se.third)) {
				sqlBuilder.append(" and " + se.thirdSql + "=?");
				parmList.add(c.getPara(paramName));
			}
		}
		if (!xx.isEmpty(se.order))
			sqlBuilder.append(se.order);

		String sql = sqlBuilder.toString();

		Object[] paras = new Object[parmList.size()];
		parmList.toArray(paras);

		String key = sql;
		for (Object obj : paras) {
			key += "_" + obj.toString();
		}
		List<Record> list = Db.use(se.ds).findByCache(BaseCache.EXP, key, sql, paras);
		// 初始化首项
		// initItemToList(isMultiple, list);

		return list;
	}
}
